package com.stockz.downloaderx;

import java.io.BufferedReader;
import java.io.FileReader;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import org.springframework.util.StringUtils;

import com.stockz.core.model.Bar;
import com.stockz.core.model.Exchange;
import com.stockz.downloaderx.Downloader.Callback.EVENT;
import com.stockz.downloaderx.Downloader.Callback.TYPE;
import com.stockz.downloaderx.util.DownloaderUtil;

public abstract class AbstractBredthDownloader extends AbstractDownloader implements BreadthDownloader {
	public abstract List<Bar> parse(String text, Exchange exchange);
	public abstract String constructUri(Date date);
	public abstract String downloadRawData(String uri);
	
	private String getRawDataFromFilebase(Date date, Exchange exchange){
		String rawData = "";
		  try{
	        	 BufferedReader bufferedReader = new BufferedReader(
			        		new FileReader(DownloaderUtil.getDownloadFilePath(date, exchange.getCode())));
	        	 String line = null;
	        	 while((line = bufferedReader.readLine()) != null){
	        		 rawData += line+"\n";
	        	 }
	        	 bufferedReader.close();
	        }catch(Exception e){

	        }
		  return rawData;
	}
	
	
	private String downloadRawData(Date date, Exchange exchange){
		String rawData = getRawDataFromFilebase(date, exchange);
        if(!StringUtils.hasText(rawData)){
        	String downloadUri = constructUri(date);
    		rawData = downloadRawData(downloadUri);
        }
        return rawData;
	}
	
	private List<Bar> parseRawData(String rawData, Date date, Exchange exchange){
		List<Bar> barList = parse(rawData,exchange);
        for(Bar bar : barList){
        	bar.setDate(date);
        }
        return barList;
	}
	
	public void download(Exchange exchange, Date startDate, Date endDate,
			List<Callback> callbackList) {
		try{
			setRunning(true);
			downloadInternal(exchange, startDate, endDate, callbackList);
		}finally{
			setRunning(false);
		}
	}
	
	private void downloadInternal(Exchange exchange, Date startDate, Date endDate,
			List<Callback> callbackList) {
		if(exchange != null && startDate != null && endDate != null
				&& endDate.after(startDate) && callbackList != null
				&& !callbackList.isEmpty()){
			reset();
			Calendar calendar = Calendar.getInstance();
			calendar.setTime(startDate);
			Download download = new Download();
			download.setBarList(null);
			download.setStartDate(startDate);
			download.setEndDate(endDate);
			download.setDownloadDate(calendar.getTime());
			download.setExchange(exchange);
			download.setScrip(null);
			
			try{
				
				executeCallbacks(download, EVENT.ALL, TYPE.START, callbackList);
				while(!calendar.getTime().after(endDate)){
					try{
						if(isCancelRequested()){
							break;
						}
						
						calendar.add(Calendar.DATE, 1);
						
						if(Calendar.SUNDAY == calendar.get(Calendar.DAY_OF_WEEK) 
								|| Calendar.SATURDAY == calendar.get(Calendar.DAY_OF_WEEK)){
							continue;
						}
						download.setDownloadDate(calendar.getTime());
						executeCallbacks(download, EVENT.LOOP, TYPE.START, callbackList);
						
						String rawData = "";
						executeCallbacks(download, EVENT.DOWNLOAD, TYPE.START, callbackList);
						try{
							download.setRawData(rawData);
							rawData = downloadRawData(calendar.getTime(), exchange);
							download.setRawData(rawData);
							executeCallbacks(download, EVENT.DOWNLOAD, TYPE.SUCCESS, callbackList);
						}catch(Exception e){
							executeCallbacks(download, EVENT.DOWNLOAD, TYPE.FAIL, callbackList);
						}finally{
							executeCallbacks(download, EVENT.DOWNLOAD, TYPE.END, callbackList);
						}
						if(!StringUtils.hasText(rawData)){
			            	continue;
						}
							
						 /*
			             * Parse action
			             */
			            try{
							executeCallbacks(download, EVENT.PARSE, TYPE.START, callbackList);
							List<Bar> barList = parseRawData(rawData, calendar.getTime(), exchange);
				            download.setBarList(barList);
				            executeCallbacks(download, EVENT.PARSE, TYPE.SUCCESS, callbackList);
			            }catch(Throwable t){
			            	executeCallbacks(download, EVENT.PARSE, TYPE.FAIL, callbackList);
			            }finally{
			            	executeCallbacks(download, EVENT.PARSE, TYPE.END, callbackList);
			            }
			            executeCallbacks(download, EVENT.LOOP, TYPE.SUCCESS, callbackList);
					}catch(Throwable t){
						executeCallbacks(download, EVENT.LOOP, TYPE.FAIL, callbackList);
					}finally{
						executeCallbacks(download, EVENT.LOOP, TYPE.END, callbackList);
					}
				}
				executeCallbacks(download, EVENT.ALL, TYPE.SUCCESS, callbackList);
			}catch(Throwable e){
				executeCallbacks(download, EVENT.ALL, TYPE.FAIL, callbackList);
			}finally{
				executeCallbacks(download, EVENT.ALL, TYPE.END, callbackList);
			}
		}
	}

}
